// 示例
{
  function *hello () {
    console.log('start without next______________')
    yield 'hello'
    yield 'world'
    console.log('mid______________')
    return 'ending'
    console.log('ending_______________')
  }
  const g = hello()
  // start without next______________  { value: 'hello', done: false } 说明函数调用next()之前,内部的代码时一句都没执行
  console.log(g.next()) 
  console.log(g.next()) // { value: 'world', done: false } 打印出了world,但是没打印出mid
  console.log(g.next()) // { value: 'ending', done: true } mid______________  ending 没打印出来
}

// 生成器种不用yield的情况
{
  function *f() {
    console.log('执行了')
  }
  const gene = f()
  console.log(gene.next()) // 执行了  { value: undefined, done: true }
  console.log(gene.next()) // { value: undefined, done: true }
}

// yield表达式用在另一个表达式之中
{
  function *demo () {
    console.log('hello_first' + (yield 13))
    console.log('hello_sec' + (yield 123))
  }
  const ge = demo()
  // yield with expression { value: 13, done: false }   没打印出hello 说明先yield,console.log放在了yield后面
  console.log('yield with expression', ge.next()) 

  // hello_first undefined  yield with expression { value: 123, done: false }
  console.log('yield with expression', ge.next())
  // hello_sec undefined yield with expression { value: undefined, done: true }
  console.log('yield with expression', ge.next())
}
// 将Generator函数赋值给对象的Iterator属性，使得对象可遍历
{
  const myI = {}
  myI[Symbol.iterator] = function *() {
    yield 1
    yield 2
    yield 3
  }
  console.log([...myI]) // [ 1, 2, 3 ]
}

// Generator函数执行后返回的遍历器对象的Symbol.iterator属性执行后返回自身
{
  function *gen() {}
  const g = gen()
  console.log(g[Symbol.iterator]() === g)
}

// next参数

{
  function *foo(x) {
    const y = 2 * (yield (x + 1))
    const z = yield (y / 3)
    return (x + y + z)
  }
  const a = foo(5)
  console.log(a.next()) // { value: 6, done: false }
  console.log(a.next()) // { value: NaN, done: false }
  console.log(a.next()) // { value: NaN, done: true }

  const b = foo(5)
  console.log(b.next()) // 6
  console.log(b.next(12)) // 2 * 12 / 3 = 8
  console.log(b.next(13)) // 5 + 24 + 13 = 42
}

// next参数2
{
  function *dataConsumer() {
    console.log('start')
    console.log(`1. ${yield}`)
    console.log(`2 ${yield} `)
    return 'result'
  }
  let getObj = dataConsumer()
  getObj.next()
  getObj.next('a')
  getObj.next('b')
}
// for...of不需要手动调用next方法
{
  function *foo () {
    yield 1
    yield 2
    yield 3
    yield 4
    return 5
  }
  for(let v of foo()) {
    console.log(v) // 1 2 3 4
  }
}
// 通过添加Generator接口，使得对象可遍历
{
  function *objectEntries(obj) {
    let propsKeys = Reflect.ownKeys(obj)
    console.log(propsKeys[Symbol.iterator]) // [Function: values]  所以能用for...of
    for (let propKey of propsKeys) {
      yield [propKey, obj[propKey]]
    }
  }
  let jane = {first: 'Hane', lase: 'Doe'}
  for (let [key, value] of objectEntries(jane)) {
    console.log(`${key}: ${value}`)
  }
  // first: Jane
  // lase: Doe


  // 另一种写法
  function *objectEntries2 () {
    let propsKeys = Object.keys(this)
    console.log('propsKeys', propsKeys)
    for (let propsKey of propsKeys) {
      yield [propsKey, this[propsKey]]
    }
  }
  let jane2 = {first: 'Hane', lase: 'Doe'}
  jane2[Symbol.iterator] = objectEntries2
  for (let [key, value] of jane2) {
    console.log(`${key}: ${value}`)
  }
}

// 直接调用Generator返回的遍历器对象
{
  function *numbers () {
    yield 1
    yield 2
    return 3
    yield 4
  }
  console.log([...numbers()]) // [1, 2]
  console.log(Array.from(numbers())) // [1, 2]
  let [x, y] = numbers()
  console.log(x) // 1
  console.log(y) // 2
  for (let v of numbers()) {
    console.log(v) // 1  2
  }
}

// Generator.prototype.throw()
{
  var g = function *() {
    try {
      yield 'result';
    } catch(e) {
      console.log('内部捕获', e) // 内部捕获 a
    }
  }
  var i = g()
  console.log(i.next()) // { value: 'result', done: false }

  try {
    i.throw('a')
    i.throw('b')
  } catch (e) {
    console.log('外部捕获', e) // 外部捕获 b
  }
}

// throw方法附带执行下一行yield表达式
{
  var gen = function *() {
    try {
      yield 'a'
    } catch (e) {
      console.log('捕获到外部抛出的错误')
    }
    yield 'b'
    yield 'c'
  }
  var g = gen()
  console.log(g.next()) // { value: 'a', done: false }
  console.log(g.throw()) // 捕获到外部抛出的错误  { value: 'b', done: false }
  console.log(g.next()) // { value: 'c', done: false }
}
// Generator.prototype.return()
{
  function *gen () {
    yield 1
    yield 2
    yield 3
  }
  var g = gen()
  console.log(g.next()) // { value: 1, done: false }
  console.log(g.return('foo')) // { value: 'foo', done: true }
  console.log(g.next()) // { value: undefined, done: true }
}

{
  const configExport = {
    activity: {
      saveSceneImage: '/pdm/service/activity/saveSceneImage',
      saveSceneVideo: '/pdm/service/activity/saveSceneVideo',
    },
    a: 'a____________________________'
  }
  function parsePath(path) {
    const bailRE = /[^\w.$]/
    if (bailRE.test(path)) {
      return
    }
    let obj = configExport
    var segments = path.split('.')
    for (var i = 0; i < segments.length; i++) {
      obj = obj[segments[i]]
    }
    return obj
  }
  console.log(parsePath('activity.saveSceneImage'))
  console.log(parsePath('activity.saveSceneVideo'))
  console.log(parsePath('a'))
  console.log(parsePath('activity.saveSceneImage'))
  console.log(parsePath('activity.saveSceneVideo'))
  console.log(parsePath('a'))
}

// 异步操作的同步化表达
{
  function request (url) { // 模拟请求
    setTimeout(() => {
      itRequest.next('response with ' + url) // 执行yield之后的代码
    }, 2000)
  }
  function *main() {
    var result = yield request('http://ww.baidu.com')
    console.log('result________________', result)
  }
  var itRequest = main()
  itRequest.next()
}